package cn.demoncat.util.lang.entity;

import com.alibaba.fastjson.annotation.JSONField;

import java.util.ArrayList;
import java.util.List;

/**
 * 描述：分页
 * 
 * 注意：因为页长页码等使用int，所以总数大于MAX_INT时分页会报错
 * 
 * @author 延晓磊
 *
 * @since 2015年7月10日
 */
public class Pager<T> {

	/**
	 * 最大页长
	 */
	public static final int MAX_PAGE_SIZE = 10000;
	/**
	 * 默认页长
	 */
	public static final int DEFAULT_PAGE_SIZE = 10;

	/**
	 * 空分页对象
	 */
	public static final Pager<Object> EMPTY_PAGER = new Pager<>();

	/**
	 * 当前页号
	 */
	private int pageNum = 1;
	/**
	 * 当前页长
	 */
	private int pageSize = DEFAULT_PAGE_SIZE;
	/**
	 * 页偏移
	 */
	private long pageStart = 0;
	/**
	 * 总记录数
	 */
	private long totalCount = 0L;
	/**
	 * 总页数
	 */
	private int pageCount = 1;
	/**
	 * 结果集
	 */
	private List<T> list = new ArrayList<>();
	/**
	 * 滚动查询ID
	 */
	private String scrollId;
	/**
	 * 扩展数据
	 */
	private Object ext;
	/**
	 * 临时数据
	 */
	@JSONField(serialize = false, deserialize = false)
	private Object temp;

	/**
	 * 
	 * 功能描述：构造方法
	 *
	 */
	public Pager() {
		super();
	}

	/**
	 * 功能描述：构造方法，拷贝
	 */
	public Pager(Pager<?> pager){
		super();
		this.pageNum = pager.getPageNum();
		this.pageSize = pager.getPageSize();
		this.pageStart = pager.getPageStart();
		this.totalCount = pager.getTotalCount();
		this.pageCount = pager.getPageCount();
	}

	/**
	 * 功能描述：构造方法，初始化分页参数
	 */
	public Pager(Integer pageNum, Integer pageSize) {
		super();
		PageParam ps = initPageParams(pageNum, pageSize);
		this.pageNum = ps.getPageNum();
		this.pageSize = ps.getPageSize();
		this.pageStart = ps.getPageStart();
	}

	/**
	 * 功能描述：构造方法，初始化分页参数（根据总数重新分配页号）
	 */
	public Pager(Integer pageNum, Integer pageSize, Long totalCount) {
		super();
		PageParam ps = initPageParams(pageNum, pageSize);
		this.pageNum = getPageNum(totalCount, ps.getPageNum(), ps.getPageSize());
		this.pageSize = ps.getPageSize();
		this.pageStart = ps.getPageNum() == this.pageNum ? ps.getPageStart() : getPageStart(this.pageNum, this.pageSize);
		this.totalCount = totalCount;
		this.pageCount = getPageCount(this.totalCount, this.pageSize);
	}

	/**
	 * 功能描述：初始化分页参数
	 *
	 * 注：String,Integer等基本类型的参数会传值而非引用，所以修改值不会影响原引用
	 * 
	 * @param pageNum
	 * @param pageSize
	 * 
	 * @return Integer[pageNum,pageSize]
	 * @author 延晓磊
	 *
	 * @since 2017年7月16日
	 */
	public static int[] initPageParam(Integer pageNum, Integer pageSize) {
		PageParam param = initPageParams(pageNum, pageSize);
		// 修改基本类型参数，不会影响原引用，所以需要返回结果
		return new int[] { param.getPageNum(), param.getPageSize() };
	}

	/**
	 * 功能描述：初始化分页参数
	 *
	 * 注：String,Integer等基本类型的参数会传值而非引用，所以修改值不会影响原引用
	 * 
	 * @param pageNum
	 * @param pageSize
	 * 
	 * @return {pageNum,pageSize}
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年7月16日
	 */
	public static PageParam initPageParams(Integer pageNum, Integer pageSize) {
		return PageParam.build(pageNum, pageSize);
	}

	/**
	 * 根据页号和页长，计算页初始索引
	 * 
	 * @param pageNum
	 * @param pageSize
	 * 
	 * @return 页初始索引
	 */
	public static long getPageStart(int pageNum, int pageSize) {
		return (pageNum - 1) * (long)pageSize;
	}

	/**
	 * 功能描述：根据总数和页长，计算总页数
	 *
	 * @param totalCount
	 * @param pageSize
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年7月16日
	 */
	public static int getPageCount(long totalCount, int pageSize) {
		if (totalCount < pageSize) {
			return 1;
		} else {
			int pageCount = (int) (totalCount / pageSize);
			if (totalCount % pageSize > 0) {
				pageCount = pageCount + 1;
			}
			return pageCount;
		}
	}

	/**
	 * 功能描述：根据总数和页长，计算页号
	 *
	 * @param totalCount	总数
	 * @param pageNum		小于1时设为1，大于实际页数时设为末页
	 * @param pageSize		页长
	 * 
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2017年7月16日
	 */
	public static int getPageNum(long totalCount, int pageNum, int pageSize) {
		if (pageNum <= 1) {
			return 1;
		}
		// 总页数
		int maxPage = 1;
		if (totalCount > pageSize) {
			maxPage = (int) (totalCount / pageSize);
			if (totalCount % pageSize > 0) {
				maxPage = maxPage + 1;
			}
		}
		// 当前页号
		return Math.min(pageNum, maxPage);
	}

	/**
	 * 绑定总数，重置页数
	 *
	 * @param totalCount
	 */
	public void bindTotalCount(long totalCount){
		this.totalCount = totalCount;
		this.pageCount = getPageCount(totalCount, this.getPageSize());
	}

	public int getPageNum() {
		return pageNum;
	}

	public void setPageNum(int pageNum) {
		this.pageNum = pageNum;
	}

	public int getPageSize() {
		return pageSize;
	}

	public void setPageSize(int pageSize) {
		this.pageSize = pageSize;
	}

	public long getPageStart() {
		return pageStart;
	}

	public void setPageStart(long pageStart) {
		this.pageStart = pageStart;
	}

	public long getTotalCount() {
		return totalCount;
	}

	public void setTotalCount(long totalCount) {
		this.totalCount = totalCount;
	}

	public int getPageCount() {
		return pageCount;
	}

	public void setPageCount(int pageCount) {
		this.pageCount = pageCount;
	}

	public List<T> getList() {
		return list;
	}

	public Pager<T> setList(List<T> list) {
		this.list = list;
		return this;
	}

	public String getScrollId() {
		return scrollId;
	}

	public void setScrollId(String scrollId) {
		this.scrollId = scrollId;
	}

	public Object getExt() {
		return ext;
	}

	public void setExt(Object ext) {
		this.ext = ext;
	}

	public Object getTemp() {
		return temp;
	}

	public void setTemp(Object temp) {
		this.temp = temp;
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (!(o instanceof Pager)) return false;

		Pager<?> pager = (Pager<?>) o;

		if (getPageNum() != pager.getPageNum()) return false;
		if (getPageSize() != pager.getPageSize()) return false;
		if (getPageStart() != pager.getPageStart()) return false;
		if (getTotalCount() != pager.getTotalCount()) return false;
		if (getPageCount() != pager.getPageCount()) return false;
		if (getList() != null ? !getList().equals(pager.getList()) : pager.getList() != null) return false;
		if (getScrollId() != null ? !getScrollId().equals(pager.getScrollId()) : pager.getScrollId() != null)
			return false;
		return getExt() != null ? getExt().equals(pager.getExt()) : pager.getExt() == null;
	}

	@Override
	public int hashCode() {
		int result = getPageNum();
		result = 31 * result + getPageSize();
		result = 31 * result + (int) (getPageStart() ^ (getPageStart() >>> 32));
		result = 31 * result + (int) (getTotalCount() ^ (getTotalCount() >>> 32));
		result = 31 * result + getPageCount();
		result = 31 * result + (getList() != null ? getList().hashCode() : 0);
		result = 31 * result + (getScrollId() != null ? getScrollId().hashCode() : 0);
		result = 31 * result + (getExt() != null ? getExt().hashCode() : 0);
		return result;
	}

	@Override
	public String toString() {
		return "Pager{" +
				"pageNum=" + pageNum +
				", pageSize=" + pageSize +
				", pageStart=" + pageStart +
				", totalCount=" + totalCount +
				", pageCount=" + pageCount +
				", list=" + list +
				", scrollId='" + scrollId + '\'' +
				", ext=" + ext +
				'}';
	}
}